/**
 * 
 */
package neptune.web.client.view.components.editor;

import java.util.ArrayList;

import neptune.web.client.model.SerializableVmTemplate;
import neptune.web.client.model.topology.SerializableCpu;
import neptune.web.client.model.topology.SerializableLink;
import neptune.web.client.model.topology.SerializableNode;
import neptune.web.client.model.topology.SerializableOperativeSystem;
import neptune.web.client.model.topology.SerializableSoftware;
import neptune.web.client.model.topology.SerializableTopology;
import neptune.web.client.services.ApplicationDataProvider;
import neptune.web.client.view.input.DefaultInputValidator;
import neptune.web.client.view.input.FloatInputValidator;
import neptune.web.client.view.input.IntegerInputValidator;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * @author Roberto Bifulco [RobertoBifulco.it] [info@robertoBifulco.it]
 * 
 */
public class NodePropsDialog extends DialogBox {

	private TextBox id;
	private TextBox description;
	private TextBox cpuName;
	private TextBox cpuType;
	private TextBox cpuClock;
	private TextBox ram;
	private TextBox hd;
	private TextBox osName;
	private TextBox osVersion;
	private TextBox osUsername;
	private TextBox osPassword;
	private ListBox software;
	private FlexTable mainPanel;
	private FlexTable cpuTable;
	private FlexTable osTable;

	private ClickListener okListener = new ClickListener() {
		public void onClick(Widget sender) {
			if (validateInputs()) {
				String oldValue = node.getId();

				updateNodeIdReferences(id.getText());
				node.setId(id.getText());
				node.setDescription(description.getText());
				if (node.getCpu() == null)
					node.setCpu(new SerializableCpu());
				node.getCpu().setName(cpuName.getText());
				node.getCpu().setType(cpuType.getText());
				if (!cpuClock.getText().equals(""))
					node.getCpu()
							.setClock(Integer.parseInt(cpuClock.getText()));
				node.setRam(Integer.parseInt(ram.getText()));
				node.setHd(Float.parseFloat(hd.getText()));
				if (node.getOperativeSystem() == null)
					node.setOperativeSystem(new SerializableOperativeSystem());
				node.getOperativeSystem().setName(osName.getText());
				node.getOperativeSystem().setVersion(osVersion.getText());
				node.getOperativeSystem()
						.setAdminUsername(osUsername.getText());
				node.getOperativeSystem()
						.setAdminPassword(osPassword.getText());
				node.setSoftwareTemplate(software.getItemText(software
						.getSelectedIndex()));
				node.setControlPort(Integer.parseInt(ssh.getText()));

				// Aggiornamento albero
				NodeMenuBar widget = (NodeMenuBar) treeItem.getWidget();
				widget.getRootItem().setText(node.getId());

				// Aggiornamento grago
				Label w1 = null;
				for (int i = 0; i < editor.getGraphPanel().getWidgetCount(); i++) {
					if (editor.getGraphPanel().getWidget(i) instanceof Label) {
						Label label = (Label) editor.getGraphPanel().getWidget(
								i);
						if (label.getText().equals(oldValue)) {
							w1 = label;
							break;
						}
					}
				}
				if (w1 != null) {
					w1.setText(node.getId());
				}

				NodePropsDialog.this.hide();
			}
		}

		private void updateNodeIdReferences(String newNodeId) {
			if (newNodeId.equals(node.getId()))
				return;

			SerializableTopology top = editor.getTopology();

			for (SerializableLink link : top.getLinks()) {
				if (link.getSource() != null) {
					if (node.getId().equals(link.getSource().getNodeId())) {
						link.getSource().setNodeId(newNodeId);
					}
				}
				if (link.getDestination() != null) {
					if (node.getId().equals(link.getDestination().getNodeId())) {
						link.getDestination().setNodeId(newNodeId);
					}

				}
			}
		}
	};
	private ClickListener cancelListener = new ClickListener() {
		public void onClick(Widget sender) {
			if (cancelCallback != null)
				cancelCallback.onCancel();
			NodePropsDialog.this.hide();
		}
	};
	private SerializableNode node;
	private TreeItem treeItem;
	private TextBox ssh;
	private final TopologyEditor editor;
	private CancelCallBack cancelCallback;
	private ChangeListener softwareChangeListener = new ChangeListener() {
		public void onChange(Widget sender) {
			ListBox softLB = (ListBox) sender;
			String template = softLB.getItemText(softLB.getSelectedIndex());

			if (template.equals(""))
				return;

			SerializableVmTemplate templateObj = null;
			for (SerializableVmTemplate vmTemp : ApplicationDataProvider
					.getInstance().getVmTemplates()) {
				if (vmTemp.getId().equals(template))
					templateObj = vmTemp;
			}

			if (templateObj == null)
				return;

			setOsPanel(templateObj.getOs());
			node.setOperativeSystem(templateObj.getOs());

			ssh.setText(Integer.toString(templateObj.getControlPort()));
			node.setControlPort(templateObj.getControlPort());

			node.setSoftwareTemplate(templateObj.getId());
			node.setInstalledSoftwares(templateObj.getSws());

			/*
			 * Aggiorna gli elementi software del tree
			 */
			treeItem.getChild(1).removeItems();
			for (SerializableSoftware serSoft : node.getInstalledSoftwares()) {
				(new AddSoftwareGraphicCommand(node, serSoft, treeItem))
						.execute();
			}

		}
	};

	/**
	 * 
	 */
	public NodePropsDialog(SerializableNode node, TreeItem treeItem,
			TopologyEditor editor) {
		super(false, true);

		this.treeItem = treeItem;
		this.editor = editor;

		mainPanel = new FlexTable();
		mainPanel.setWidth("95%");
		ScrollPanel mainPanelWrapper = new ScrollPanel(mainPanel);
		mainPanelWrapper.setHeight("350px");

		/*
		 * Inizio costruzione campi per inserimemnto dati
		 */
		// ID
		Label idLabel = new Label("Node id");
		idLabel.setStylePrimaryName("NodePropsDialog-label");
		id = new TextBox();
		id.setStylePrimaryName("NodePropsDialog-input");
		mainPanel.setWidget(0, 0, idLabel);
		mainPanel.setWidget(0, 1, id);

		// DESCRIPTION
		Label descrLabel = new Label("Description");
		descrLabel.setStylePrimaryName("NodePropsDialog-label");
		description = new TextBox();
		description.setStylePrimaryName("NodePropsDialog-input");
		mainPanel.setWidget(1, 0, descrLabel);
		mainPanel.setWidget(1, 1, description);

		// CPU
		DisclosurePanel cpuPanel = new DisclosurePanel("CPU");
		cpuPanel.setStylePrimaryName("NodePropsDialog-inputPanel");
		cpuPanel.setAnimationEnabled(true);
		cpuPanel.setWidth("100%");
		mainPanel.setWidget(2, 0, cpuPanel);
		mainPanel.getFlexCellFormatter().setColSpan(2, 0, 2);

		cpuTable = new FlexTable();
		cpuTable.setWidth("100%");
		cpuPanel.add(cpuTable);

		// cpu name
		Label cpuNameLabel = new Label("Name");
		cpuNameLabel.setStylePrimaryName("NodePropsDialog-label");
		cpuName = new TextBox();
		cpuName.setStylePrimaryName("NodePropsDialog-input");
		cpuTable.setWidget(0, 0, cpuNameLabel);
		cpuTable.setWidget(0, 1, cpuName);

		// cpu type
		Label cpuTypeLabel = new Label("Type");
		cpuTypeLabel.setStylePrimaryName("NodePropsDialog-label");
		cpuType = new TextBox();
		cpuType.setStylePrimaryName("NodePropsDialog-input");
		cpuTable.setWidget(1, 0, cpuTypeLabel);
		cpuTable.setWidget(1, 1, cpuType);

		// cpu clock
		Label cpuClockLabel = new Label("Clock");
		cpuClockLabel.setStylePrimaryName("NodePropsDialog-label");
		cpuClock = new TextBox();
		cpuClock.setStylePrimaryName("NodePropsDialog-input");
		cpuTable.setWidget(2, 0, cpuClockLabel);
		cpuTable.setWidget(2, 1, cpuClock);

		// RAM
		Label ramLabel = new Label("RAM (MBs)");
		ramLabel.setStylePrimaryName("NodePropsDialog-label");
		ram = new TextBox();
		ram.setText("256");
		ram.setStylePrimaryName("NodePropsDialog-input");
		mainPanel.setWidget(3, 0, ramLabel);
		mainPanel.setWidget(3, 1, ram);

		// HD
		Label hdLabel = new Label("HardDisk (GBs)");
		hdLabel.setStylePrimaryName("NodePropsDialog-label");
		hd = new TextBox();
		hd.setText("2");
		hd.setStylePrimaryName("NodePropsDialog-input");
		mainPanel.setWidget(4, 0, hdLabel);
		mainPanel.setWidget(4, 1, hd);

		// OS
		DisclosurePanel osPanel = new DisclosurePanel("Operative System");
		osPanel.setStylePrimaryName("NodePropsDialog-inputPanel");
		osPanel.setAnimationEnabled(true);
		osPanel.setWidth("100%");
		mainPanel.setWidget(5, 0, osPanel);
		mainPanel.getFlexCellFormatter().setColSpan(5, 0, 2);

		osTable = new FlexTable();
		osTable.setWidth("100%");
		osPanel.add(osTable);

		// os name
		Label osNameLabel = new Label("Name");
		osNameLabel.setStylePrimaryName("NodePropsDialog-label");
		osName = new TextBox();
		osName.setEnabled(false);
		osName.setStylePrimaryName("NodePropsDialog-input");
		osTable.setWidget(0, 0, osNameLabel);
		osTable.setWidget(0, 1, osName);

		// os version
		Label osVersionLabel = new Label("Version");
		osVersionLabel.setStylePrimaryName("NodePropsDialog-label");
		osVersion = new TextBox();
		osVersion.setEnabled(false);
		osVersion.setStylePrimaryName("NodePropsDialog-input");
		osTable.setWidget(1, 0, osVersionLabel);
		osTable.setWidget(1, 1, osVersion);

		// os username
		Label osUsernameLabel = new Label("Username");
		osUsernameLabel.setStylePrimaryName("NodePropsDialog-label");
		osUsername = new TextBox();
		osUsername.setText("root");
		osUsername.setEnabled(false);
		osUsername.setStylePrimaryName("NodePropsDialog-input");
		osTable.setWidget(2, 0, osUsernameLabel);
		osTable.setWidget(2, 1, osUsername);

		// os password
		Label osPasswordLabel = new Label("Password");
		osPasswordLabel.setStylePrimaryName("NodePropsDialog-label");
		osPassword = new TextBox();
		osPassword.setStylePrimaryName("NodePropsDialog-input");
		osTable.setWidget(3, 0, osPasswordLabel);
		osTable.setWidget(3, 1, osPassword);

		// SOFTWARE TEMPLATE
		Label softwareLabel = new Label("Software template");
		softwareLabel.setStylePrimaryName("NodePropsDialog-label");
		software = new ListBox();
		software.setStylePrimaryName("NodePropsDialog-input");
		mainPanel.setWidget(6, 0, softwareLabel);
		mainPanel.setWidget(6, 1, software);

		software.addItem("");
		ArrayList<SerializableVmTemplate> vmTmps = ApplicationDataProvider
				.getInstance().getVmTemplates();
		for (SerializableVmTemplate serializableVmTemplate : vmTmps) {
			software.addItem(serializableVmTemplate.getId());
		}
		software.setSelectedIndex(0);

		software.addChangeListener(softwareChangeListener);

		// SSH PORT
		Label sshLabel = new Label("Ssh server port");
		sshLabel.setStylePrimaryName("NodePropsDialog-label");
		ssh = new TextBox();
		ssh.setEnabled(false);
		ssh.setStylePrimaryName("NodePropsDialog-input");
		mainPanel.setWidget(7, 0, sshLabel);
		mainPanel.setWidget(7, 1, ssh);

		// BUTTON PANEL
		HorizontalPanel buttonPanel = new HorizontalPanel();
		Button ok = new Button("Ok");
		ok.addClickListener(okListener);
		ok.setStylePrimaryName("NodePropsDialog-button");
		Button cancel = new Button("Cancel");
		cancel.addClickListener(cancelListener);
		cancel.setStylePrimaryName("NodePropsDialog-button");
		buttonPanel.add(ok);
		buttonPanel.add(cancel);

		VerticalPanel vPanel = new VerticalPanel();
		vPanel.setWidth("100%");
		vPanel.add(mainPanelWrapper);
		vPanel.add(buttonPanel);
		vPanel.setCellHorizontalAlignment(buttonPanel,
				VerticalPanel.ALIGN_RIGHT);

		this.setWidget(vPanel);
		this.setText("Node Properties");

		// Styles
		mainPanelWrapper.setStylePrimaryName("NodePropsDialog-mainWrapper");
		mainPanel.setStylePrimaryName("NodePropsDialog-mainPanel");
		this.setStylePrimaryName("NodePropsDialog");

		setData(node);
	}

	public boolean validateInputs() {
		// Resetta le segnalazioni d'errore
		id.removeStyleDependentName("error");
		cpuName.removeStyleDependentName("error");
		cpuType.removeStyleDependentName("error");
		cpuClock.removeStyleDependentName("error");
		ram.removeStyleDependentName("error");
		hd.removeStyleDependentName("error");
		osName.removeStyleDependentName("error");
		osVersion.removeStyleDependentName("error");
		osUsername.removeStyleDependentName("error");
		osPassword.removeStyleDependentName("error");
		software.removeStyleDependentName("error");
		ssh.removeStyleDependentName("error");

		DefaultInputValidator defaultValidator = new DefaultInputValidator();
		IntegerInputValidator integerValidator = new IntegerInputValidator();
		FloatInputValidator floatValidator = new FloatInputValidator();

		boolean[] errors = new boolean[12];
		for (int i = 0; i < errors.length; i++)
			errors[i] = true;

		if (!defaultValidator.isValid(id.getText())) {
			errors[0] = false;
			id.addStyleDependentName("error");
		}
		if (!defaultValidator.isValid(cpuName.getText())
				&& !cpuName.getText().equals("")) {
			errors[1] = false;
			cpuName.addStyleDependentName("error");
		}
		if (!defaultValidator.isValid(cpuType.getText())
				&& !cpuType.getText().equals("")) {
			errors[2] = false;
			cpuType.addStyleDependentName("error");
		}
		if (!integerValidator.isValid(cpuClock.getText())
				&& !cpuClock.getText().equals("")) {
			errors[3] = false;
			cpuClock.addStyleDependentName("error");
		}
		if (!integerValidator.isValid(ram.getText())) {
			errors[4] = false;
			ram.addStyleDependentName("error");
		}
		try
		{
			Integer integer=new Integer(ram.getText());
			if ( integer.intValue() < 256 )
			{
				errors[4] = false;
				ram.addStyleDependentName("error");
			}
		}
		catch(java.lang.Exception e)
		{
			errors[4] = false;
			ram.addStyleDependentName("error");
		}
		if (!floatValidator.isValid(hd.getText())) {
			errors[5] = false;
			hd.addStyleDependentName("error");
		}
		if (!defaultValidator.isValid(osName.getText())) {
			errors[6] = false;
			osName.addStyleDependentName("error");
		}
		if (!defaultValidator.isValid(osVersion.getText())) {
			errors[7] = false;
			osVersion.addStyleDependentName("error");
		}
		if (!defaultValidator.isValid(osUsername.getText())) {
			errors[8] = false;
			osUsername.addStyleDependentName("error");
		}
		if (!defaultValidator.isValid(osPassword.getText())) {
			errors[9] = false;
			osPassword.addStyleDependentName("error");
		}
		if (!defaultValidator.isValid(software.getItemText(software
				.getSelectedIndex()))) {
			errors[10] = false;
			software.addStyleDependentName("error");
		}
		if (!integerValidator.isValid(ssh.getText())) {
			errors[11] = false;
			ssh.addStyleDependentName("error");
		}

		for (int i = 0; i < errors.length; i++) {
			if (!errors[i])
				return false;
		}

		return true;
	}

	private void setOsPanel(SerializableOperativeSystem os) {
		if (os != null) {
			osName.setText(os.getName());
			osVersion.setText(os.getVersion());
			osUsername.setText(os.getAdminUsername());
			osPassword.setText(os.getAdminPassword());
		}
	}

	public void setData(SerializableNode data) {
		id.setText(data.getId());
		description.setText(data.getDescription());
		if (data.getCpu() != null) {
			cpuName.setText(data.getCpu().getName());
			cpuType.setText(data.getCpu().getType());
			cpuClock.setText(Integer.toString(data.getCpu().getClock()));
		}
		ram.setText(Integer.toString(data.getRam()));
		hd.setText(Float.toString(data.getHd()));
		setOsPanel(data.getOperativeSystem());

		int selectedIndex = 0;
		for (int i = 0; i < software.getItemCount(); i++) {
			if (software.getItemText(i).equals(data.getSoftwareTemplate()))
				selectedIndex = i;
		}
		software.setSelectedIndex(selectedIndex);
		ssh.setText(Integer.toString(data.getControlPort()));

		this.node = data;
	}

	/**
	 * @return the cancelCallback
	 */
	public CancelCallBack getCancelCallback() {
		return cancelCallback;
	}

	/**
	 * @param cancelCallback
	 *            the cancelCallback to set
	 */
	public void setCancelCallback(CancelCallBack cancelCallback) {
		this.cancelCallback = cancelCallback;
	}
}
